package com.midian.common.filter;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import javax.annotation.Resource;

import net.sf.json.JSONObject;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.midian.common.filter.annotation.Validate;
import com.midian.common.filter.util.ClazzMsgUtil;
import com.midian.common.system.ErrorConstants;
import com.midian.common.system.RetManager;
import com.midian.common.system.SysStatic;
import com.midian.common.utils.CheckUtils;
import com.midian.model.user.User;
import com.midian.service.user.IUserService;

/**
 * 控制器接口信息处理拦截器
 * @author Mengfh
 *
 */
public class OpMsgInterceptor implements MethodInterceptor {
	
	/**log日志对象*/
	private static final Logger LOG = Logger.getLogger(OpMsgInterceptor.class);
	
	/**用户业务*/
	private IUserService userService;

	@Resource(name = "userService")
	public void setUserService(IUserService userService) {
		this.userService = userService;
	}

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		//获取被拦截的目标方法
		Method method = invocation.getMethod();
		//获取目标对象
		Object target = invocation.getThis();
		//获取目标方法的验证注解
		Validate validate = method.getAnnotation(Validate.class);
		//异常错误码
		String retCode = "";
		//需要进行验证的情况
		if(validate != null) {
			//获取方法参数注解集合
			Annotation[][] paramAnnotations = method.getParameterAnnotations();
			//获取方法参数名称集合
			String[] paramNames = ClazzMsgUtil.getMethodParamNames(target.getClass(), method.getName(), method.getParameterTypes());
			//替换参数名称列表(如果通过RequestParam注解指定了参数的名称，进行替换)
			replaceParamNames(paramAnnotations, paramNames);
			//获取方法参数值集合
			Object[] params = invocation.getArguments();
			//参数验证处理
			JSONObject json = opParams(paramAnnotations, paramNames, params);
			//如果JSON对象不为空，即存在参数验证的错误信息，直接返回带错误信息的JSON对象
			if(json != null) {
				//如果是token错误的，打印token错误日志
				if (RetManager.common_token_error.equals(json.get(RetManager.RET_CODE))) {
					LOG.error(getOpErrorMsg(method, target, RetManager.common_token_error));
				}
				return json;
			}
			//获取异常错误码
			retCode = validate.retCode();
		}
		
		Object result = new Object();
		//配置了异常错误码的情况，进行异常处理
		if(StringUtils.isNotBlank(retCode)) {
			try {
				result = invocation.proceed();
			} catch (Exception e) {
				e.printStackTrace();
				//生成异常错误的JSON对象
				JSONObject json = new JSONObject();
				setRet(json, RetManager.common_error, retCode);
				result = json;
				//打印操作错误日志
				LOG.error(getOpErrorMsg(method, target, e.getMessage()));
			}
		} else {
		//没有配置异常错误码的情况，直接执行目标方法
			result = invocation.proceed();
		}
		if(result instanceof JSONObject) {
			JSONObject json = (JSONObject) result;
			//如果JSON对象中不包含ret 将其ret_code 设为no_tip
			if(!json.containsKey(RetManager.RET)) {
				setRet(json, RetManager.common_success, RetManager.common_no_tip);
			}
			return json;
		}
		return result;
	}
	
	/**
	 * 获取处理后的错误信息
	 * @param method 目标方法
	 * @param target 目标对象
	 * @param baseErrorMsg 基本错误信息
	 * @return
	 */
	private String getOpErrorMsg(Method method, Object target, String baseErrorMsg) {
		RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
		String url = requestMapping.value()[0]; //获取方法请求的URL
		//错误格式：[目标类名/URL] 异常信息
		StringBuilder errSb = new StringBuilder();
		errSb.append("[").append(target.getClass().getSimpleName()).append(url).append("] ").append(baseErrorMsg);
		return errSb.toString();
	}
	
	/**
	 * 参数验证处理
	 * @param paramAnnotations 参数注解列表
	 * @param paramNames 参数名称列表
	 * @param params 参数值列表
	 * @param checkLogin 是否检测登录状态
	 * @return
	 */
	private JSONObject opParams(Annotation[][] paramAnnotations, String[] paramNames, Object[] params) {
		HashMap<String, String> paramMap = new HashMap<String, String>();
		String access_token = null; //token
		String user_id = null; //用户id
		List<String> paramNameList = Arrays.asList(paramNames);
		//当参数列表中同时包含access_token和user_id时，才进行登录验证
		boolean checkLogin = paramNameList.contains("access_token") && paramNameList.contains("user_id");
		Integer userObjIndex = null;
		if(paramAnnotations.length == params.length) {
			for(int i = 0; i < paramAnnotations.length; i++) {
				Annotation[] annotations = paramAnnotations[i]; //获取参数的注解列表
				String paramName = paramNames[i]; //获取参数名称
				Object paramVal = params[i]; //获取参数值
				//参数为client_key的情况，进行client_key验证
				if("client_key".equals(paramName)) {
					String client_key = String.valueOf(paramVal); //获取client_key
					
					System.out.println("----------------client_key:---------------"+client_key);
					
					//client_key验证
					JSONObject json = new JSONObject();
					try {
						json = CheckUtils.checkClientKey(client_key.replace("\n", ""));
					} catch (Exception e) {
						setRet(json, RetManager.common_error, RetManager.common_client_key_error);
					}
					//如果发生异常或者返回了错误码，直接返回
					if ("error".equals(json.get("ret"))) {
						return json;
					}
				}
				//需要验证登录的情况，获取token与用户id
				if("access_token".equals(paramName)) {
					access_token = paramVal != null ? String.valueOf(paramVal) : ""; //获取token值
					
					System.out.println("----------------access_token:---------------"+access_token);
					
				} else if("user_id".equals(paramName)) {
					user_id = paramVal != null ? String.valueOf(paramVal) : ""; //获取用户id
					
					System.out.println("----------------user_id:---------------"+user_id);
					
				}
				Integer requestParamIndex = getRequestParamIndex(annotations); //获取参数中RequestParam注解的下标
				//参数没有配置注解或者不存在RequestParam注解的情况，保存需要非空验证的参数
				if(annotations.length == 0 || requestParamIndex == null) {
					saveNeedValidateParam(paramMap, paramName, paramVal);
				} else {
				//参数配置了RequestParam注解的情况
					RequestParam requestParam = (RequestParam) annotations[requestParamIndex];
					if(requestParam.required()) {
						//如果required为true，保存需要进行非空验证的参数
						saveNeedValidateParam(paramMap, paramName, paramVal);
					} else if("access_token".equals(paramName)) {
						checkLogin = checkLogin && StringUtils.isNotBlank(access_token); //登录验证须确保token不为空
					} else if("user_id".equals(paramName)) {
						checkLogin = checkLogin && StringUtils.isNotBlank(user_id); //登录验证须确保userId不为空
					}
				}
				if("loginUser".equals(paramName)) {
					userObjIndex = i;
				}
			}
		}
		
		//进行参数的非空验证
		if(!paramMap.isEmpty()) {
			JSONObject json = CheckUtils.checkParam(paramMap);
			if (json != null && "error".equals(json.get("ret"))) {
				return json;
			}
		}
		
		//需要验证登录的情况
		if(checkLogin) {
			User user = this.userService.getUserByToken(access_token, user_id);
			//如果获取的用户对象为空，提示错误码
			JSONObject json = new JSONObject();
			if (user == null) {
				setRet(json, RetManager.common_error, RetManager.common_token_error);
				return json;
			} else if(SysStatic.DELFLAG.equals(user.getDelFlag())) {
			//如果用户对象不为空，但用户已被禁用，提示错误信息
				setRet(json, RetManager.common_error, RetManager.common_user_disable);
				return json;
			} else if(userObjIndex != null) {
			//如果用户对象不为空，并且设置了User类型的参数，将User类型的参数更新为当前登录者的用户对象
				params[userObjIndex] = user;
			}
		}
		return null;
	}
	
	/**
	 * 获取参数中RequestParam注解的下标
	 * @param annotations 参数的注解列表
	 * @return 返回参数中RequestParam注解下标，如果不存在返回null
	 */
	private Integer getRequestParamIndex(Annotation[] annotations) {
		for(int i = 0; i < annotations.length; i++) {
			if(annotations[i] instanceof RequestParam) {
				return i;
			}
		}
		return null;
	}
	
	/**
	 * 替换参数名称列表(如果通过RequestParam或PathVariable注解指定了参数的名称，进行替换)
	 * @param paramAnnotations 方法的注解集合
	 * @param paramNames 方法的参数名称集合
	 */
	private void replaceParamNames(Annotation[][] paramAnnotations, String[] paramNames) {
		if(paramAnnotations.length != 0 && paramNames.length != 0 && paramAnnotations.length == paramNames.length) {
			for(int i = 0; i < paramAnnotations.length; i++) {
				Annotation[] annotations = paramAnnotations[i];
				for (Annotation annotation : annotations) {
					String defParamName = null; //指定的参数名称
					//如果通过RequestParam或PathVariable注解指定了参数的名称，替换原来的参数名
					if(annotation instanceof RequestParam) {
						RequestParam requestParam = (RequestParam) annotation;
						defParamName = requestParam.value(); //获取RequestParam注解指定的参数名称
					} else if(annotation instanceof PathVariable) {
						PathVariable pathVariable = (PathVariable) annotation;
						defParamName = pathVariable.value(); //获取PathVariable注解指定的参数名称
					}
					if(StringUtils.isNotBlank(defParamName)) {
						paramNames[i] = defParamName; //替换原来的参数名称
						break;
					}
				}
			}
		}
	}
	
	/**
	 * 保存需要进行非空验证的参数
	 * @param paramMap 非空验证参数Map
	 * @param paramName 参数名称
	 * @param paramVal 参数值
	 */
	private void saveNeedValidateParam(HashMap<String, String> paramMap, String paramName, Object paramVal) {
		paramMap.put(paramName, paramVal != null ? String.valueOf(paramVal) : null);
	}
	
	/**
	 * 设置结果
	 * @param json 
	 * @param ret ret的值
	 * @param retCode ret_code的值
	 */
	private void setRet(JSONObject json ,String ret,String retCode){
		json.put(RetManager.RET, ret); //设置状态为成功
		json.put(RetManager.RET_CODE, retCode); //设置状态为成功
		json.put(RetManager.RET_INFO, RetManager.getInstance().getRetInfo(retCode)); 

	}
}
